package com.ysj.aipicturebe.job;

import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ysj.aipicturebe.model.dto.picture.PictureQueryRequest;
import com.ysj.aipicturebe.model.entity.Picture;
import com.ysj.aipicturebe.model.enums.PictureReviewStatusEnum;
import com.ysj.aipicturebe.service.PictureService;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.util.DigestUtils;

import javax.annotation.Resource;
import java.util.concurrent.TimeUnit;

/**
 * 缓存预热任务 - 优化版
 */
@Component
@Slf4j
public class PreCacheJob {

    @Resource
    private PictureService pictureService;

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    @Resource
    private RedissonClient redissonClient;

    // 配置项
    private static final String LOCK_KEY = "ai_picture:precachejob:docache:lock";
    private static final String CACHE_KEY_PREFIX = "ai_picture:recommend:page:";
    private static final int MAX_PAGE = 10; // 最大页数
    private static final int PAGE_SIZE = 12; // 每页大小
    private static final long CACHE_TTL_MINUTES = 30; // 缓存有效期（分钟）
    private static final String SORT_FIELD = "createTime";
    private static final boolean IS_ASC = false;
    //每天晚上12点执行预热任务
    @Scheduled(cron = "0 0 0 * * ?")
    public void doCacheRecommendPicture() {
        RLock lock = redissonClient.getLock(LOCK_KEY);
        try {
            // 默认 Redisson WatchDog 机制支持自动续期，获取锁时不指定过期时间即可
            if (lock.tryLock(0, TimeUnit.SECONDS)) {
                log.info("获取预热任务锁成功，线程 ID: {}", Thread.currentThread().getId());

                ValueOperations<String, String> redisOps = stringRedisTemplate.opsForValue();

                for (int i = 1; i <= MAX_PAGE; i++) {

                    // 构造 PictureQueryRequest，模拟分页请求参数（注意：必须与接口参数一致）
                    PictureQueryRequest pictureQueryRequest = new PictureQueryRequest();
                    pictureQueryRequest.setCurrent(i);
                    pictureQueryRequest.setPageSize(PAGE_SIZE);
                    pictureQueryRequest.setReviewStatus(PictureReviewStatusEnum.PASS.getValue());

                    // 构造 key
                    String queryCondition = JSONUtil.toJsonStr(pictureQueryRequest);
                    String hashKey = DigestUtils.md5DigestAsHex(queryCondition.getBytes());
                    String redisKey = String.format("aipcture:listPictureVOByPage:%s", hashKey);

                    QueryWrapper<Picture> queryWrapper = new QueryWrapper<>();
                    queryWrapper.orderBy(StrUtil.isNotEmpty(SORT_FIELD), IS_ASC, SORT_FIELD);

                    Page<Picture> picturePage = pictureService.page(new Page<>(i, PAGE_SIZE), queryWrapper);

                    if (picturePage == null || picturePage.getRecords().isEmpty()) {
                        log.warn("第 {} 页无图片数据，跳过缓存", i);
                        continue;
                    }


                    String jsonStr = JSONUtil.toJsonStr(picturePage);

                    try {
                        redisOps.set(redisKey, jsonStr, CACHE_TTL_MINUTES, TimeUnit.MINUTES);
                        log.info("缓存预热成功 -> key: {}, 条数: {}", redisKey, picturePage.getRecords().size());
                    } catch (Exception e) {
                        log.error("写入 Redis 缓存失败，key: {}", redisKey, e);
                    }
                }

            } else {
                log.info("未获取到锁，当前已有其他实例执行任务");
            }
        } catch (InterruptedException e) {
            log.error("预热任务执行中断", e);
        } finally {
            if (lock.isHeldByCurrentThread()) {
                lock.unlock();
                log.info("释放预热任务锁，线程 ID: {}", Thread.currentThread().getId());
            }
        }
    }
}
